#ifndef _BASIC_H
#define _BASIC_H
// ······································//
// ············WiFi section··············//
// ······································//

void connectWiFi()
{
  WiFi.begin(ssid, password);     // 启动网络连接
  Serial.print("Connecting to "); // 串口监视器输出网络连接信息
  Serial.print(ssid);
  Serial.println(" ..."); // 告知用户NodeMCU正在尝试WiFi连接

  int i = 0; // 这一段程序语句用于检查WiFi是否连接成功
  while (WiFi.status() != WL_CONNECTED)
  {                // WiFi.status()函数的返回值是由NodeMCU的WiFi连接状态所决定的。
    ESP.wdtFeed(); // avoid resst accidently
    delay(500);    // 如果WiFi连接成功则返回值为WL_CONNECTED
    i++;
    Serial.print('.'); // 此处通过While循环让NodeMCU每隔一秒钟检查一次WiFi.status()函数返回值
    ESP.wdtFeed();     // avoid resst accidently
    if (i >= 10)
      break;
  }
  if (WiFi.status() == WL_CONNECTED)
  {
    Serial.println("");                        // WiFi连接成功后
    Serial.println("Connection established!"); // NodeMCU将通过串口监视器输出"连接成功"信息。
    Serial.print("IP address:    ");           // 同时还将输出NodeMCU的IP地址。这一功能是通过调用
    Serial.println(WiFi.localIP());            // WiFi.localIP()函数来实现的。该函数的返回值即NodeMCU的IP地址。
    wifi_state = 1;                            // 告知系统WIFI状态
  }
  else
  {
    for (i = 0; i < 3; i++)
    {
      String FS_MOUNT_POINT;
      // 上电后读取复位前的数据
      switch (i)
      {
      case 0:
        FS_MOUNT_POINT = "/data0";
        break;
      case 1:
        FS_MOUNT_POINT = "/data1";
        break;
      case 2:
        FS_MOUNT_POINT = "/data2";
        break;
      }
      File file = SPIFFS.open(FS_MOUNT_POINT + "/data.txt", "r");
      if (!file)
      {
        Serial.println("无法打开文件！");
      }
      wea[i].code_day = file.readStringUntil('\n').toInt();
      wea[i].code_night = file.readStringUntil('\n').toInt();
      wea[i].wind_direction = file.readStringUntil('\n').toInt();
      wea[i].high = file.readStringUntil('\n').toInt();
      wea[i].low = file.readStringUntil('\n').toInt();
      wea[i].rain = file.readStringUntil('\n').toInt();
      wea[i].wind_scale = file.readStringUntil('\n').toInt();

      Serial.printf("========Day%d========\n", i);
      Serial.printf("Day Weather:%d\n ", wea[i].code_day);
      Serial.printf("Night Weather:%d\n", wea[i].code_night);
      // tempreture
      Serial.printf("High:%d°C\n", wea[i].high);
      Serial.printf("Low:%d°C\n", wea[i].low);

      Serial.printf("Rainfall:%d %\n ", wea[i].rain);
      Serial.printf("Wind Direction:%d\n ", wea[i].wind_direction);
      Serial.printf("Wind Scale:%d\n", wea[i].wind_scale);
      // 关闭文件
      Serial.println("READ SUCCESSDULLY");
      file.close();
    }

    wifi_state = 0;
    Serial.println("");                   // WiFi连接成功后
    Serial.println("Connection falsed!"); // NodeMCU将通过串口监视器输出"连接成功"信息。
  }
}

void detactwifi()
{
  if (WiFi.status() != WL_CONNECTED)
  {
    Serial.println("WiFi disconnected!");
    wifi_state = 0;
    Serial.printf("wificonnected:%d\n", wifi_state); // for test
  }
  else
  {
    wifi_state = 1;
  }
}

// ······································//
// ···········DFPlayer section···········//
// ······································//// DFPlayer section

void dfplayerinit()
{
  Serial.println(F("Building connection with dfplayer "));
  if (!myDFPlayer.begin(mySoftwareSerial))
  { // Use softwareSerial to communicate with mp3.
    Serial.println('.');
  }
  myDFPlayer.volume(volume); // Set volume value. From 0 to 30
  Serial.println(F("DFPlayer Mini online."));

  // myDFPlayer.loopFolder(folder_playing);
  switch (folder_playing)
  {
  case 2:
    document_playing = folder2_lastplayed_document;
    break;
  case 3:
    document_playing = folder3_lastplayed_document;
    break;
  }
  myDFPlayer.playFolder(folder_playing, document_playing); // 播放上次关闭前的曲目
  uint8_t current_play_min = 0;
  uint8_t current_play_sec = 0; // 置零以便计算播放时间
}

void printDetail(uint8_t type, int value)
{
  switch (type)
  {
  case TimeOut:
    Serial.println(F("Time Out!"));
    break;
  case WrongStack:
    Serial.println(F("Stack Wrong!"));
    break;
  case DFPlayerCardInserted:
    Serial.println(F("Card Inserted!"));
    break;
  case DFPlayerCardRemoved:
    Serial.println(F("Card Removed!"));
    break;
  case DFPlayerCardOnline:
    Serial.println(F("Card Online!"));
    break;
  case DFPlayerUSBInserted:
    Serial.println("USB Inserted!");
    break;
  case DFPlayerUSBRemoved:
    Serial.println("USB Removed!");
    break;
  case DFPlayerPlayFinished:
    Serial.print(F("Number:"));
    Serial.print(value);
    Serial.println(F(" Play Finished!"));
    if (loop && value > 93 /*此时播放的不是服务语音内容*/)
      document_playing++;
    current_play_min = 0;
    current_play_sec = 0;
    delay(1000); // avoid print twice in a info
    break;
  case DFPlayerError:
    Serial.print(F("DFPlayerError:"));
    switch (value)
    {
    case Busy:
      Serial.println(F("Card not found"));
      break;
    case Sleeping:
      Serial.println(F("Sleeping"));
      break;
    case SerialWrongStack:
      Serial.println(F("Get Wrong Stack"));
      break;
    case CheckSumNotMatch:
      Serial.println(F("Check Sum Not Match"));
      break;
    case FileIndexOut:
      Serial.println(F("File Index Out of Bound"));

      break;
    case FileMismatch:
      Serial.println(F("Cannot Find File"));
      document_playing = 1; // 在该文件夹没有找着，超出文件夹文件数目循环播放第一个
      Serial.printf("playindoc%d\n", document_playing);
      delay(1000); // avoid print twice in a info
      break;
    case Advertise:
      Serial.println(F("In Advertise"));
      break;
    default:
      break;
    }
    break;
  default:
    break;
  }
}

// ······································//
// ············Timer section·············//
// ······································//

void timerISR()
{
  if (current_play_sec == 20 || current_play_sec == 0 || current_play_sec == 40)
    oled_state++;
  if (oled_state > 2)
    oled_state = 0;
  if (!pause)
    current_play_sec++;
  if (current_play_sec >= 60)
  {
    current_play_min++;
    current_play_sec = 0;
  }

  if (time_now.min % 5 == 0 && time_now.sec <= 30)
  {
    state = 2;
    oled_state = 1;
  }

  if (time_now.min == 0 && (time_now.hour >= 14 && time_now.hour <= 19) && time_now.sec <= 8 /*防止持续报时*/)
  {
    state = 1;
    Serial.printf("报时:%d", time_now.hour);
  }

  if (state == 2)
  {
    if (time_now.sec == 20 || time_now.sec == 0 || time_now.sec == 40)
      oled_state++;
  }

  time_now.sec++;
  if (time_now.sec >= 60)
  {
    time_now.min++;
    time_now.sec = 0;
  }
  if (time_now.min >= 60)
  {
    time_now.hour++;
    time_now.min = 0;
  }
  if (time_now.hour >= 24)
  {
    time_now.hour = 0;
    time_now.day++;
  }
}
// NTP server
const int NTP_PACKET_SIZE = 48;     // NTP time is in the first 48 bytes of message
byte packetBuffer[NTP_PACKET_SIZE]; // buffer to hold incoming & outgoing packets

// send an NTP request to the time server at the given address
void sendNTPpacket(IPAddress &address)
{
  // set all bytes in the buffer to 0
  memset(packetBuffer, 0, NTP_PACKET_SIZE);
  // Initialize values needed to form NTP request
  // (see URL above for details on the packets)
  packetBuffer[0] = 0b11100011; // LI, Version, Mode
  packetBuffer[1] = 0;          // Stratum, or type of clock
  packetBuffer[2] = 6;          // Polling Interval
  packetBuffer[3] = 0xEC;       // Peer Clock Precision
  // 8 bytes of zero for Root Delay & Root Dispersion
  packetBuffer[12] = 49;
  packetBuffer[13] = 0x4E;
  packetBuffer[14] = 49;
  packetBuffer[15] = 52;
  // all NTP fields have been given values, now
  // you can send a packet requesting a timestamp:
  Udp.beginPacket(address, 123); // NTP requests are to port 123
  Udp.write(packetBuffer, NTP_PACKET_SIZE);
  Udp.endPacket();
}

time_t getNtpTime()
{
  IPAddress ntpServerIP; // NTP server's ip address

  while (Udp.parsePacket() > 0)
    ; // discard any previously received packets
  Serial.println("Transmit NTP Request");
  // get a random server from the pool
  WiFi.hostByName(ntpServerName, ntpServerIP);
  Serial.print(ntpServerName);
  Serial.print(": ");
  Serial.println(ntpServerIP);
  sendNTPpacket(ntpServerIP);
  uint32_t beginWait = millis();
  while (millis() - beginWait < 1500)
  {
    int size = Udp.parsePacket();
    if (size >= NTP_PACKET_SIZE)
    {
      Serial.println("Receive NTP Response");
      Udp.read(packetBuffer, NTP_PACKET_SIZE); // read packet into the buffer
      unsigned long secsSince1900;
      // convert four bytes starting at location 40 to a long integer
      secsSince1900 = (unsigned long)packetBuffer[40] << 24;
      secsSince1900 |= (unsigned long)packetBuffer[41] << 16;
      secsSince1900 |= (unsigned long)packetBuffer[42] << 8;
      secsSince1900 |= (unsigned long)packetBuffer[43];
      return secsSince1900 - 2208988800UL + timeZone * SECS_PER_HOUR;
    }
  }
  Serial.println("No NTP Response :-(");
  return 0; // return 0 if unable to get the time
}

void gettime()
{

  if (timeStatus() != timeNotSet)
  {
    if (now() != prevDisplay)
    { // update the display only if time has changed
      prevDisplay = now();
      time_now.min = minute();
      time_now.hour = hour();
      time_now.sec = second();
      time_now.day = day();
      time_now.month = month();
      time_now.year = year();
    }
  }
  Serial.print(time_now.sec);
  Serial.print(" ");
  Serial.print(time_now.min);
  Serial.print(" ");
  Serial.print(time_now.hour);
  Serial.println(" ");
}
// ······································//
// ··············Key section·············//
// ······································//
void key_init()
{
  swSerial.begin(9600); // Initialize swSerial
}

void key_detaction()
{
  Keypad.checkChanges(); // let the key scan library to update key status
  if (Keypad.isKeyChanged() == true)
  {                                  // if there is any detectable key change
    key_code = Keypad.getKeyValue(); // print key value on Serial (use Serial Monitor to see it!)
  }

  switch (key_code)
  {
  case NEXT:
    pause = 0;
    document_playing++;
    key_code = 100;
    break;

  case PREVIOUS:
    pause = 0;
    document_playing--;
    key_code = 100;
    break;
  case PAUSE_CONTINUE:
    pause = !pause;
    if (pause)
      myDFPlayer.pause(); // pause the mp3
    else
      myDFPlayer.start(); // start the mp3 from the pause
    key_code = 100;
    break;
  case ADD_CATOGORY:
    folder_playing++;
    if (folder_playing >= folder_num_max)
      folder_playing = 2;
    switch (folder_playing)
    {
    case 2:
      document_playing = folder2_lastplayed_document;
      break;
    case 3:
      document_playing = folder3_lastplayed_document;
      break;
    }
    key_code = 100;
    break;
  case SUB_CATOGORY:
    folder_playing--;
    if (folder_playing <= 1)
      folder_playing = folder_num_max;
    switch (folder_playing)
    {
    case 2:
      document_playing = folder2_lastplayed_document;
      break;
    case 3:
      document_playing = folder3_lastplayed_document;
      break;
    }
    key_code = 100;
    break;

  case WEATHER_0:
    state = 3;
    weather_to_broadcast = 0;
    key_code = 100;
    break;
  case WEATHER_1:
    state = 3;
    weather_to_broadcast = 1;
    key_code = 100;
    break;
  case WEATHER_2:
    state = 3;
    weather_to_broadcast = 2;
    key_code = 100;
    break;
  case TIME:
    state = 1;
    key_code = 100;
    break;
  case ADD_VOLUME:
    myDFPlayer.volumeUp(); // Volume Up
    key_code = 100;
    volume++;
    if (volume>=30)
    {
      volume=30;
    }
    

    break;
  case SUB_VOLUME:
    myDFPlayer.volumeDown(); // Volume Down
    key_code = 100;
        volume--;
    if (volume<=0)
    {
      volume=0;
    }
    
    break;

  case POWER:
    // wait to enter
    pause = !pause;
    power = !power;
    digitalWrite(power_control, power);
    if (power)
    {
      dfplayerinit();
      u8g2.begin();
      u8g2.drawXBMP(0, 0, 128, 64, boot2);
      u8g2.sendBuffer();
      current_play_min = 0;
      current_play_sec = 0;
      // WiFi.forceSleepWake(); // Wifi on
      Serial.println("wifi on");
    }
    else
    {
      // WiFi.forceSleepBegin(); // Wifi off
      Serial.println("wifi off");
    }
    // ESP.deepSleep(0);//ESP8266 enter deep sleep mode

    Serial.println("power switch");
    key_code = 100;
    break;
  default:
    break;
  }
}

// ······································//
// ············State section·············//
// ······································//

void state_switch()
{
  // 0-playmusic 1-timebroadcast 2-timedisplay 3-weatherbroadcast
  switch (state)
  {
  case 0:
    normalplay();       // dfplayer //this function have no affact under function
    switch (oled_state) // oled
    {
      // 0-播放+天气
      //  1-播放+汉字
      //  2-播放+日期

    case 0 /* constant-expression */:
      print_mainpage_wea_num(current_play_min * 100 + current_play_sec);
      break;
    case 1:
      print_mainpage_charplaying();
      break;
    case 2:
      print_mainpage_md_num(current_play_min * 100 + current_play_sec);
      break;
    }
    break;

  case 1:
    print_mainpage_md_num(time_now.hour * 100 + time_now.min); // oled
    myDFPlayer.volume(25);
    time_broadcast(); // dfplayer
    myDFPlayer.volume(volume);
    state = 0;       // 当播报完毕后就回去继续播放曲目
    folder_cash = 1; // 更改cash来达到重新播放的目的
    break;
  case 2:
    //   myDFPlayer.pause();
    switch (oled_state) // oled
    {
      //  0-时间+天气
      //  1-时间+汉字
      //  2-时间+日期

    case 0 /* constant-expression */:
      print_mainpage_wea_num(time_now.hour * 100 + time_now.min);
      break;
    case 1:
      print_mainpage_chartime();
      break;
    case 2:
      print_mainpage_md_num(time_now.hour * 100 + time_now.min);
      break;
    }
    if (time_now.min != 0 && time_now.sec > 30)
      state = 0;
    break;
  case 3:
    // myDFPlayer.disableLoop();  //disable loop.
    // weather_broadcast_oleddisplay(0);
    // myDFPlayer.enableLoop();  //enable loop.//can not disable the loop actually
    loop_state = 0;
    myDFPlayer.reset(); // reset to clean the loop info
    delay(100);         // wait for reset
    myDFPlayer.volume(25);
    weather_broadcast_oleddisplay(weather_to_broadcast);
    myDFPlayer.volume(volume);
    state = 0;
    folder_cash = 1;
    loop_state = 1;
    break;

  default:
    break;
  }
}

#endif